/*
 * short_message.cpp
 *
 *  Created on: 2008-12-2
 *      Author: fanliangliang
 */

#include "short_message.h"
#include "xml_config.h"
#include "toxic.h"

ShortMessage::ShortMessage()
:_text()
,_phoneNumbers() {

}

ShortMessage::~ShortMessage() {

}

bool ShortMessage::setText(const string& text) {
	string temp;
	codeConvert(&temp, text, "gb2312", "utf-8");
	_text = truncate(temp, 255);
	return _text.size() == temp.size();
}

bool ShortMessage::addPhoneNumber(const string& phoneNumber) {
	if (_phoneNumbers.size() < 255) {
		_phoneNumbers.push_back(truncate(phoneNumber, 255));
		return true;
	}
	return false;
}

const string& ShortMessage::text() const {
	return _text;
}

size_t ShortMessage::phoneNumberCount() const {
	return _phoneNumbers.size();
}

const string& ShortMessage::phoneNumberAt(size_t index) const {
	return _phoneNumbers.at(index);
}

size_t ShortMessage::packageLength() const {
	size_t length = _text.size() + 10;
	size_t phoneNumberCount = _phoneNumbers.size();
	for (size_t i = 0; i < phoneNumberCount; ++i) {
		length += _phoneNumbers[i].size() + 1;
	}
	return length;
}

size_t ShortMessage::package(char* buffer, size_t length) const {
	unsigned short totalLength = static_cast<unsigned short>(packageLength());
	if (length < totalLength) {
		return 0;
	}

	totalLength = htons(totalLength);
	unsigned short sync = htons(0x3E3E);
	unsigned short version = htons(0x0001);
	unsigned short cmd = htons(0x0001);
	unsigned char textSize = static_cast<unsigned char>(_text.size());
	unsigned char phoneNumberCount = static_cast<unsigned char>(_phoneNumbers.size());

	char* pos = buffer;

	// package head
	memcpy(pos, &sync, sizeof(sync));
	pos += sizeof(sync);

	memcpy(pos, &version, sizeof(version));
	pos += sizeof(version);

	memcpy(pos, &cmd, sizeof(cmd));
	pos += sizeof(cmd);

	memcpy(pos, &totalLength, sizeof(totalLength));
	pos += sizeof(totalLength);

	// package body
	memcpy(pos, &textSize, sizeof(textSize));
	pos += sizeof(textSize);

	memcpy(pos, _text.c_str(), textSize);
	pos += textSize;

	memcpy(pos, &phoneNumberCount, sizeof(phoneNumberCount));
	pos += sizeof(phoneNumberCount);

	for (size_t i = 0; i < phoneNumberCount; ++i) {
		const string& phoneNumber = _phoneNumbers[i];
		unsigned char phoneNumberLength = static_cast<unsigned char>(phoneNumber.size());
		memcpy(pos, &phoneNumberLength, sizeof(phoneNumberLength));
		pos += sizeof(phoneNumberLength);

		memcpy(pos, phoneNumber.c_str(), phoneNumberLength);
		pos += phoneNumberLength;
	}
	return pos - buffer;
}

#define CHECK_EQUAL(pos, field, value) \
	unsigned short field; \
	memcpy(&field, pos, sizeof(field)); \
	pos += sizeof(field); \
	if (ntohs(field) != value) { \
		return false; \
	}

#define CHECK_GREATER_EQUAL(pos, field, value) \
	unsigned short field; \
	memcpy(&field, pos, sizeof(field)); \
	pos += sizeof(field); \
	if (ntohs(field) < value) { \
		return false; \
	}

bool ShortMessage::unpackage(const char* buffer, size_t length) const {
	if (length != 10) {
		return false;
	}

	const char* pos = buffer;

	CHECK_EQUAL(pos, sync, 0x3E3E)
	CHECK_GREATER_EQUAL(pos, version, 0x0001)
	CHECK_EQUAL(pos, cmd, 0x0002)
	CHECK_EQUAL(pos, totalLength, length)
	CHECK_EQUAL(pos, result, 0)

	return true;
}

string ShortMessage::truncate(const string& s, size_t size) {
	return s.size() > size ? s.substr(0, size) : s;
}
